package com.sau.pixelcart.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sau.pixelcart.common.constant.InventoryConstant;
import com.sau.pixelcart.common.constant.ProductConstant;
import com.sau.pixelcart.common.exception.BusinessException;
import com.sau.pixelcart.common.result.PageResult;
import com.sau.pixelcart.domain.dto.InventoryPageDTO;
import com.sau.pixelcart.domain.dto.ProductDTO;
import com.sau.pixelcart.domain.dto.ProductPageDTO;
import com.sau.pixelcart.domain.entity.Category;
import com.sau.pixelcart.domain.entity.InventoryAlert;
import com.sau.pixelcart.domain.entity.Product;
import com.sau.pixelcart.domain.entity.ProductInventory;
import com.sau.pixelcart.domain.vo.InventoryVO;
import com.sau.pixelcart.domain.vo.InventoryViewVO;
import com.sau.pixelcart.mapper.CategoryMapper;
import com.sau.pixelcart.mapper.InventoryAlertMapper;
import com.sau.pixelcart.mapper.ProductInventoryMapper;
import com.sau.pixelcart.mapper.ProductMapper;
import com.sau.pixelcart.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品实时库存表 服务实现类
 * </p>
 *
 * @author Inton
 * @since 2025-03-08
 */
@Slf4j
@Service
public class ProductInventoryServiceImpl extends ServiceImpl<ProductInventoryMapper, ProductInventory> implements IProductInventoryService {

    @Autowired
    private ProductInventoryMapper productInventoryMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private IInventoryAlertService inventoryAlertService;

    @Autowired
    private InventoryAlertMapper inventoryAlertMapper;


    // 锁等待时间
    private static final int LOCK_WAIT_TIME = 3;
    // 锁持有时间
    private static final int LOCK_LEASE_TIME = 10;

    /**
     * 批量入库
     * @param productDTOList
     */
    @Override
    @Transactional
    public void saveList(List<ProductDTO> productDTOList) {
//        //提取商品名称
//        Set<String> productIds = productDTOList.stream()
//                .map(ProductDTO::getId)
//                .collect(Collectors.toSet());
//
//        //查询现有商品库存（1次SQL）
//        List<ProductInventory> lastProductInventoryList = this.list();
//        Map<String, Integer> lastStockMap = lastProductInventoryList.stream().collect(Collectors.toMap(ProductInventory::getProductId, ProductInventory::getStock));

        //查询所有未处理的预警记录
        LambdaQueryWrapper<InventoryAlert> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(InventoryAlert::getStatus,"pending");
        Map<String, InventoryAlert> pendingMap = inventoryAlertService.list(queryWrapper).stream().collect(Collectors.toMap(InventoryAlert::getProductId, p -> p));

        //累加商品库存
        List<ProductInventory> productInventoryList = productDTOList.stream().map(productDTO -> {
            ProductInventory productInventory = ProductInventory.builder()
                    .productId(productDTO.getId())
                    .stock(productDTO.getStock())
                    .lowStockThreshold(ProductConstant.LOW_STOCK_NUM)
                    .lastUpdated(LocalDateTime.now())
                    .build();

//            //是否触发库存预警
//            inventoryAlertService.checkStockWarning(productInventory.getProductId());
            return productInventory;
        }).collect(Collectors.toList());

        //添加到库存表
        productInventoryMapper.updateBatch(productInventoryList);

        List<ProductInventory> newProductInventoryList = this.list();

        for (ProductInventory productInventory : newProductInventoryList) {
            if(pendingMap.get(productInventory.getProductId()) != null){
                //有未处理预警，再次判断
                if(productInventory.getStock() > productInventory.getLowStockThreshold()){
                    inventoryAlertService.processAlert(productInventory);
                }else{
                    //是否触发库存预警
                    inventoryAlertService.checkStockWarning(productInventory.getProductId());
                }
            }
        }

        //添加到商品表
//        productMapper.updateStockNum(productList);

    }

    /**
     * 批量出库
     * @param productList
     */
    @Override
    @Transactional
    public void outStock(List<ProductDTO> productList) {
        //取出库存商品版本
        List<ProductInventory> productInventoryList = this.list();
        Map<String, ProductInventory> productInventoryMap = productInventoryList.stream().collect(Collectors.toMap(ProductInventory::getProductId, Function.identity()));

        //使用Redisson分布式锁统一库存
        productList.stream()
                .filter(this::isValidProduct)
                .sorted((p1, p2) -> p1.getId().compareTo(p2.getId()))  // 按UUID排序避免死锁
                .forEach(product -> {
                    RLock lock = redissonClient.getLock("stock_lock:" + product.getId());
                    log.info("lock:{}",lock);
                    try {
                        // 尝试获取锁
                        if (lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS)) {

                            //扣减库存(商品id，库存，版本)
                            int operateRows = productInventoryMapper.deductStock(
                                    product.getId(),
                                    product.getStock(),
                                    productInventoryMap.get(product.getId()).getVersion()
                            );

                            if(operateRows == 0) {
                                throw new BusinessException(product.getName() + "库存不足或版本冲突");
                            }

                            // 检查库存预警
                            inventoryAlertService.checkStockWarning(product.getId());

                        } else {
                            throw new BusinessException("系统繁忙，请稍后再试");
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        throw new BusinessException("操作被中断");
                    } finally {
                        if (lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                });
    }

    private boolean isValidProduct(ProductDTO product) {
        return product.getStock() != null && product.getStock() > 0
                && product.getPrice() != null
                && product.getPrice().compareTo(BigDecimal.ZERO) > 0;
    }

    /**
     * 分页查询库存信息
     *
     * @param inventoryPageDTO
     * @return
     */
    @Override
    public PageResult<InventoryVO> pageQuery(InventoryPageDTO inventoryPageDTO) {
        Page<ProductInventory> page = new Page<>(inventoryPageDTO.getPage(), inventoryPageDTO.getPageSize());

        //设置dto中的status为查询条件，若为空，则全部展示
        //通过status查inventory_alert中的数据
        LambdaQueryWrapper<InventoryAlert> inventoryAlertLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(inventoryPageDTO.getStatus() != null){
            inventoryAlertLambdaQueryWrapper.eq(InventoryAlert::getStatus,inventoryPageDTO.getStatus());
        }
        //符合status查询条件的alertList
        List<InventoryAlert> inventoryAlertList = inventoryAlertMapper.selectList(inventoryAlertLambdaQueryWrapper);

        //当前表
        LambdaQueryWrapper<ProductInventory> productInventoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
        Page<ProductInventory> productInventoryPage = productInventoryMapper.selectPage(page, productInventoryLambdaQueryWrapper);
        List<ProductInventory> productInventoryList = productInventoryPage.getRecords();

        List<InventoryVO> inventoryVOList = productInventoryList.stream()
                .map(productInventory -> {
                    //根据商品id查商品表
                    String productId = productInventory.getProductId();
                    Product product = productMapper.selectById(productId);

                    //库存预警表中查库存状态
                    LambdaQueryWrapper<InventoryAlert> inventoryAlertLambdaQueryWrapper1 = new LambdaQueryWrapper<>();
                    inventoryAlertLambdaQueryWrapper1.eq(InventoryAlert::getProductId, productId);
                    inventoryAlertLambdaQueryWrapper1.eq(InventoryAlert::getStatus, InventoryConstant.STOCK_ALERT_PENDING);
                    InventoryAlert inventoryAlert = inventoryAlertService.getOne(inventoryAlertLambdaQueryWrapper1);

                    //获取分类name
                    Category category = categoryMapper.selectById(product.getCategoryId());

                    InventoryVO inventoryVO = new InventoryVO();
                    inventoryVO.setInventoryId(productInventory.getInventoryId());
                    inventoryVO.setStock(productInventory.getStock());
                    inventoryVO.setPrice(product.getPrice());
                    inventoryVO.setProductCode(product.getCode());
                    inventoryVO.setProductName(product.getName());
                    inventoryVO.setCategoryName(category.getName());
                    if (inventoryAlert == null) {
                        //当前商品没有预警
                        inventoryVO.setStatus(InventoryConstant.STOCK_ALERT_PROCESSED);
                    } else {
                        inventoryVO.setStatus(inventoryAlert.getStatus());
                    }
                    BigDecimal totalPrice = product.getPrice().multiply(BigDecimal.valueOf(productInventory.getStock()));
                    inventoryVO.setTotalPrice(totalPrice);
                    return inventoryVO;
                }).filter(vo -> {
                    if(inventoryPageDTO.getStatus() != null && !inventoryPageDTO.getStatus().equals("")){
                        return Objects.equals(vo.getStatus(),  inventoryPageDTO.getStatus());
                    }else{
                        return true;
                    }
                })
                .collect(Collectors.toList());

        PageResult<InventoryVO> pageResult = new PageResult<>();
        BeanUtils.copyProperties(productInventoryPage, pageResult);
        pageResult.setRecords(inventoryVOList);

        return pageResult;
    }

    /**
     * 获取库存页看板数据
     * @return
     */
    @Override
    public InventoryViewVO getView() {

        LambdaQueryWrapper<Product> productLambdaQueryWrapper = new LambdaQueryWrapper<>();
        productLambdaQueryWrapper.eq(Product::getStatus,ProductConstant.STATUS_ACTIVE);
        List<Product> productList = productMapper.selectList(productLambdaQueryWrapper);

        //库存预警表中查库存状态
        LambdaQueryWrapper<InventoryAlert> inventoryAlertLambdaQueryWrapper = new LambdaQueryWrapper<>();
        inventoryAlertLambdaQueryWrapper.eq(InventoryAlert::getStatus, InventoryConstant.STOCK_ALERT_PENDING);
        List<InventoryAlert> inventoryAlertList = inventoryAlertService.list(inventoryAlertLambdaQueryWrapper);

        List<ProductInventory> productInventoryList = this.list();

        int totalStock = productInventoryList.stream()
                .mapToInt(ProductInventory::getStock)
                .sum();


        BigDecimal totalPrice = BigDecimal.ZERO;
        Map<String, ProductInventory> productInventoryMap = productInventoryList.stream().collect(Collectors.toMap(ProductInventory::getProductId, Function.identity()));

        for (Product product : productList) {
            BigDecimal thisPrice = product.getPrice().multiply(BigDecimal.valueOf(productInventoryMap.get(product.getId()).getStock()));
            totalPrice = totalPrice.add(thisPrice);
        }

        InventoryViewVO inventoryViewVO = new InventoryViewVO();
        //预警数量
        if(inventoryAlertList != null) {
            inventoryViewVO.setAlertProduct(inventoryAlertList.size());
        }else{
            inventoryViewVO.setAlertProduct(0);
        }

        //库存总数量
        inventoryViewVO.setTotalStock(totalStock);

        //总计商品数量
        inventoryViewVO.setTotalProductNumber(productList.size());

        //库存总价值
        inventoryViewVO.setTotalPrice(totalPrice);

        return inventoryViewVO;
    }
}
